package cn.factorybox.item.service.impl;

import cn.factorybox.common.entity.PageResult;
import cn.factorybox.common.utils.UUIDUtil;
import cn.factorybox.entity.UserInfo;
import cn.factorybox.item.config.JwtProperties;
import cn.factorybox.item.mapper.FactoryDeviceDataMapper;
import cn.factorybox.item.mapper.FactoryDeviceMapper;
import cn.factorybox.item.mapper.RoomMapper;
import cn.factorybox.item.service.RoomService;
import cn.factorybox.model.entity.FactoryDeviceData;
import cn.factorybox.model.entity.Room;
import cn.factorybox.utils.JwtUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.text.DecimalFormat;
import java.util.*;

/**
 * @author flypig
 * @version 1.0
 * @date 2020-09-11 11:32
 */

@Service
public class RoomServiceImpl implements RoomService {

    @Autowired
    private RoomMapper roomMapper;

    @Autowired
    private FactoryDeviceMapper factoryDeviceMapper;

    @Autowired
    private FactoryDeviceDataMapper factoryDeviceDataMapper;

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private RedisTemplate redisTemplate;

    private Integer page;
    private Integer size;

    @Override
    public void saveRoom(HttpServletRequest request, Room room) throws Exception {
        String token = request.getHeader("token");
        UserInfo userInfo = JwtUtils.getInfoFromToken(token, this.jwtProperties.getKey());
        String companyId = userInfo.getCompanyId();
        // 获取当前公司/主管下所有房间的编号
        List<Integer> numbers = (List<Integer>) redisTemplate.opsForList().range("companyId:" + companyId, 0, -1);
        if (numbers.isEmpty()) {
            // 如果为空，则表示该公司还未创建房间，房间序号直接设为1
            room.setNumber(1);
        } else {
            for (int i = 0, j = 1; i < numbers.size(); i++, j++) {
                if (j != numbers.get(i)) {
                    room.setNumber(j);
                    break;
                }
                if (j == numbers.size()) {
                    room.setNumber(j + 1);
                }
            }
        }
        room.setCompanyId(companyId);
        room.setId(UUIDUtil.uuid());
        room.setfCreateTime(new Date());
        roomMapper.saverRoom(room);
        refreshRoomCache();     // 刷新redis缓存
    }

    @Override
    public int updateRoom(Room room) {
        return roomMapper.updateRoom(room);
    }

    @Override
    public void deleteRoom(String id) {
        // 删除房间会同时删除该房间内的设备及设备采集的数据，通过设置数据外键实现
        roomMapper.deleteRoom(id);
        refreshRoomCache();
    }

    @Override
    public Map<String, Object> selectList(Map<String, Object> map) {
        this.page = Integer.parseInt((String) map.get("page"));
        this.size = Integer.parseInt((String) map.get("size"));
        PageHelper.startPage(this.page, this.size);
        Map<String, Object> data = new HashMap<>();
        List<Map<String, Object>> results = roomMapper.selectList();
        PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(results);
        data.put("data", new PageResult<>(pageInfo.getTotal(), pageInfo.getList()));
        return data;
    }

    @Override
    public List<Room> selectShortList(HttpServletRequest request) throws Exception {
        String token = request.getHeader("token");
        UserInfo userInfo = JwtUtils.getInfoFromToken(token, this.jwtProperties.getKey());
        String companyId = userInfo.getCompanyId();
        return roomMapper.selectShortList(companyId);
    }

    @Override
    public List<Room> selectNormalList(HttpServletRequest request) throws Exception {
        String token = request.getHeader("token");
        UserInfo userInfo = JwtUtils.getInfoFromToken(token, this.jwtProperties.getKey());
        String companyId = userInfo.getCompanyId();
        return roomMapper.selectNormalList(companyId);
    }

    @Override
    public Map<String, Object> getSingleRoom(HttpServletRequest request, Integer number) throws Exception {
        Map<String, Object> data = new HashMap<>();
        DecimalFormat df = new DecimalFormat("0.00");    // 格式化数据
        String token = request.getHeader("token");
        UserInfo userInfo = JwtUtils.getInfoFromToken(token, this.jwtProperties.getKey());
        String companyId = userInfo.getCompanyId();
        // 查询该房间内最新一条数据
        FactoryDeviceData lastest = factoryDeviceDataMapper.selectLastestOfRoom(companyId, number);
        // 查找该房间内最新十五条温度、湿度数据
        List<Double> tempList = new ArrayList<>();
        List<Double> humList = new ArrayList<>();
        if (lastest != null) {
            tempList = factoryDeviceDataMapper.selectTempListOfRoom(companyId, number);
            humList = factoryDeviceDataMapper.selectHumListOfRoom(companyId, number);
        }
        // 查找当前该房间所有设备的数据总和
        Double allCount = factoryDeviceDataMapper.countAllOfRoom(companyId, number);
        // 查找正常数据总和
        Double normalCount = factoryDeviceDataMapper.countNormalOfRoom(companyId, number);
        // 查找异常数据总和
        Double warningCount = factoryDeviceDataMapper.countWarningOfRomm(companyId, number);
        Map<String, Object> count = new HashMap<>();
        Map<String, Object> rate = new HashMap<>();
        ResultOfSingleRoom result = new ResultOfSingleRoom();
        result.setHum(lastest == null ? 0 : lastest.getfHumidity());
        result.setTemp(lastest == null ? 0 : lastest.getfTemperature());
        result.setType(lastest == null ? "outline" : lastest.getState());
        count.put("all", allCount);
        count.put("normal", normalCount);
        count.put("warning", warningCount);
        rate.put("normal", allCount != 0 ? Double.valueOf(df.format(normalCount / allCount)) * 100 : 100);
        rate.put("warning", allCount != 0 ? Double.valueOf(df.format(warningCount / allCount)) * 100 : 0);
        count.put("rate", rate);
        data.put("state", result);
        data.put("temp", tempList);
        data.put("hum", humList);
        data.put("count", count);
        return data;
    }

    /**
     * 进行房间数据的缓存，将所有房间序号缓存到redis
     */
    private void refreshRoomCache() {
        // 进行房间数据的缓存，将所有房间序号缓存到redis
        List<Room> roomList = roomMapper.selectAllRoomsForRedisCache();
        // 先清空redis
        Set<String> keys = redisTemplate.keys("companyId:*");
        redisTemplate.delete(keys);     // 需要重新定义key的序列化方式，否则无法删除
        roomList.forEach(room -> {
            redisTemplate.opsForList().rightPush("companyId:" + room.getCompanyId(), room.getNumber());
        });
    }
}

class ResultOfSingleRoom {
    String type;
    Double temp;
    Double hum;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Double getTemp() {
        return temp;
    }

    public void setTemp(Double temp) {
        this.temp = temp;
    }

    public Double getHum() {
        return hum;
    }

    public void setHum(Double hum) {
        this.hum = hum;
    }
}
